package com.byron.media.server.rtsp.handlers;

import com.byron.media.server.rtsp.model.LineDelimiter;
import com.google.gson.ExclusionStrategy;
import com.google.gson.FieldAttributes;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelOutboundHandlerAdapter;
import io.netty.channel.ChannelPromise;
import lombok.extern.slf4j.Slf4j;

import java.nio.charset.CharacterCodingException;
import java.nio.charset.Charset;
import java.nio.charset.CharsetEncoder;

@Slf4j
//@ChannelHandler.Sharable
public class RtpEncoder extends ChannelOutboundHandlerAdapter {

    private final Charset charset;

    private CharsetEncoder encoder;

    private static long currentSeq = 0;         // 包名

    private final LineDelimiter delimiter;      // 一行的分隔符

    private Gson gson = new GsonBuilder().setExclusionStrategies(new ExclusionStrategy() {

        @Override
        public boolean shouldSkipField(FieldAttributes f) {
            //过滤掉字段名包含"session","container"的字段
            return f.getName().contains("session") || f.getName().contains("container");
        }

        @Override
        public boolean shouldSkipClass(Class<?> clazz) {
            //过滤掉 类名包含 Bean的类
            return clazz.getName().contains("Container");
        }

    }).create();

    public RtpEncoder() {
        this(Charset.forName("UTF8"));
    }

    public RtpEncoder(Charset charset) {
        if (charset == null) {
            throw new NullPointerException("charset");
        } else {
            this.charset = charset;
        }
        delimiter = LineDelimiter.UNIX;
    }

    @Override
    public void write(ChannelHandlerContext ctx, Object message, ChannelPromise promise) throws Exception {
        if (encoder == null) {
            encoder = charset.newEncoder();
        }

//        if(message instanceof BaseObj || message instanceof C2SHeartBeatReqObj || message instanceof S2CHeartBeatResObj){
//            String json = gson.toJson(message);
//
//            int classIndex = JsonClass.getInstance().getNumberByClass(message.getClass());
//            StringBuffer sb = new StringBuffer().append(classIndex).append("##").append(json);
//            String value = (json == null ? "" : sb.toString());
//
//            byte[] data = value.getBytes(encoder.charset());
//
//            if(classIndex != 3 && classIndex != 4){
//                log.info("send " + value);
//            }
//
//            currentSeq ++;
//            if(data.length > 1024){
//                // 分裂成多个obj发送
//                sendLongObj(ctx, data, promise, encoder);
//            } else {
//                sendShortObj(ctx, data, promise, encoder);
//            }
//        } else if(message instanceof DataObj){
//            DataObj rtpPacket = (DataObj)message;
//            sendDataObj(ctx, rtpPacket, promise);
//        } else if(message instanceof String){
            sendString(ctx, (String)message, promise);
//        }
    }

    private void sendString(ChannelHandlerContext ctx, String message, ChannelPromise promise) throws Exception {
        byte[] data = message.getBytes(encoder.charset());
        currentSeq ++;
//        if(data.length > 1024){
//            // 分裂成多个obj发送
//            sendLongObj(ctx, data, promise, encoder);
//        } else {
            sendShortObj(ctx, data, promise, encoder);
//        }
    }

//    void sendDataObj(ChannelHandlerContext ctx, DataObj dataObj, ChannelPromise promise){
//
//        String extra = dataObj.getExtra();
//        int extraLength = 0;
//        byte[] extraBytes = null;
//        if(extra == null || "".equals(extra)){
//            extraLength = 0;
//        } else {
//            extraBytes = extra.getBytes();
//            extraLength = extraBytes.length;
//        }
//        int length = dataObj.getLength() + extraLength + 8;
//
//        ByteBuf buf = ctx.alloc().buffer(length + 4);
//        buf.writeByte((byte)'$');
//        buf.writeByte((byte)0);
//        buf.writeInt(length);
//        buf.writeByte(dataObj.getDataType());
//        buf.writeByte(dataObj.getPosition());
//        buf.writeInt(dataObj.getLength());
//        buf.writeBytes(dataObj.getData(), 0, dataObj.getLength());
//        buf.writeShort((short) extraLength);
//        if(extraBytes != null){
//            buf.writeBytes(extraBytes);
//        }
////        buf.flip();
//        ctx.writeAndFlush(buf, promise);
//
////        byte[] rtp = dataObj.toArray();
////        ByteBuf buf = ctx.alloc().buffer(rtp.length + 4);
////        buf.writeByte((byte)'$');
////        buf.writeByte((byte)0);
////        buf.writeShort((short) rtp.length);
////        buf.writeBytes(rtp);
////        ctx.writeAndFlush(buf, promise);
//    }

//    /**
//     * 发送长数据（数据长度大于MTU）
//     */
//    void sendLongObj(ChannelHandlerContext ctx, byte[] data, ChannelPromise promise, CharsetEncoder encoder)  throws CharacterCodingException{
//
//        int length = data.length;
//        int count = length / 1024;
//        int left = length % 1024;
//        if(left > 0){
//            count ++;
//        }
//
//        DataObj dataObj;
//
//        int sended = 0;
//
//        for(int i = 0; i < count; i++){
//            int notSend = length - sended;
//            int bufferLength = notSend > 1024 ?  1024 : notSend;
//            byte[] splitData = new byte[bufferLength];
//            System.arraycopy(data, sended, splitData, 0, bufferLength);
//            byte position;
//            if(i == 0){
//                position = DataObj.POSITION_START;
//            } else if(i == count - 1){
//                position = DataObj.POSITION_END;
//            } else {
//                position = DataObj.POSITION_BODY;
//            }
//
//            dataObj = new DataObj(DataObj.DATA_LONG_OBJ, position, splitData, "");
//
//            sendDataObj(ctx, dataObj, promise);
//            sended += bufferLength;
//        }
//    }

    /**
     * 发送短数据（长度小于MTU）
     * @param data
     * @param promise
     * @param encoder
     */
    void sendShortObj(ChannelHandlerContext ctx, byte[] data, ChannelPromise promise, CharsetEncoder encoder) throws CharacterCodingException {
        ByteBuf buf = ctx.alloc().buffer(data.length);
        buf.writeBytes(data);
        buf.writeBytes(delimiter.getValue().getBytes());
        ctx.writeAndFlush(buf, promise);
    }
}
